package com.yds.dccjll.lib.base.util;

import android.app.Application;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;

import com.yds.dccjll.lib.base.R;
import com.yolanda.nohttp.FileBinary;
import com.yolanda.nohttp.Headers;
import com.yolanda.nohttp.NoHttp;
import com.yolanda.nohttp.RequestMethod;
import com.yolanda.nohttp.download.DownloadListener;
import com.yolanda.nohttp.download.DownloadQueue;
import com.yolanda.nohttp.download.DownloadRequest;
import com.yolanda.nohttp.error.NetworkError;
import com.yolanda.nohttp.error.NotFoundCacheError;
import com.yolanda.nohttp.error.TimeoutError;
import com.yolanda.nohttp.error.URLError;
import com.yolanda.nohttp.error.UnKnownHostError;
import com.yolanda.nohttp.rest.OnResponseListener;
import com.yolanda.nohttp.rest.Request;
import com.yolanda.nohttp.rest.RequestQueue;
import com.yolanda.nohttp.rest.Response;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.net.ProtocolException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class NoHttpUtil {

    private static final String tag = NoHttpUtil.class.getSimpleName();
    private static RequestQueue mRequestQueue;
    private static DownloadQueue mDownloadQueue;
    private static NoHttpUtil mNoHttpInstance;
    private static final int HTTP_REQUEST_SUCCESS = 0x0001;
    private static final int HTTP_REQUEST_FAIL = 0x0000;
    private static Application mApplication;

    private static final String USER_STATUS = "status";
    private static final String WHAT_VALUE = "what";
    private static ArrayList<Map<String, Object>> mSignList = new ArrayList<>();
    private static final int maxRequestNumbers = 30;

    static {
        for (int i = 0; i < maxRequestNumbers; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put(USER_STATUS, false);
            map.put(WHAT_VALUE, 1000 + i);
            mSignList.add(map);
        }
    }

    private static synchronized int assignWhatValue() {
        int what = -1;
        for (int i = 0; i < mSignList.size(); i++) {
            Map<String, Object> map = mSignList.get(i);
            if (!((boolean) map.get(USER_STATUS))) {
                map.put(USER_STATUS, true);
                mSignList.set(i, map);
                what = (int) map.get(WHAT_VALUE);
                break;
            }
        }
        return what;
    }

    private static synchronized void recoverWhatValue(int what) {
        for (int i = 0; i < mSignList.size(); i++) {
            Map<String, Object> map = mSignList.get(i);
            if (what == (int) map.get(WHAT_VALUE)) {
                map.put(USER_STATUS, false);
                mSignList.set(i, map);
                break;
            }
        }
    }

    public NoHttpUtil() {
        getNoHttpRequestQueue();
        getNoHttpDownloadQueue();
    }

    public static NoHttpUtil getInstance(Application application) {
        if (mNoHttpInstance == null) {
            synchronized (NoHttpUtil.class) {
                if (mNoHttpInstance == null) {
                    mApplication = application;
                    mNoHttpInstance = new NoHttpUtil();
                }
            }
        }
        return mNoHttpInstance;
    }

    private static RequestQueue getNoHttpRequestQueue() {
        if (mRequestQueue == null) {
            synchronized (NoHttpUtil.class) {
                if (mRequestQueue == null) {
                    NoHttp.initialize(mApplication);
                    mRequestQueue = NoHttp.newRequestQueue();
                }
            }
        }
        return mRequestQueue;
    }

    private static DownloadQueue getNoHttpDownloadQueue() {
        if (mDownloadQueue == null) {
            synchronized (NoHttpUtil.class) {
                if (mDownloadQueue == null) {
                    NoHttp.initialize(mApplication);
                    mDownloadQueue = NoHttp.newDownloadQueue();
                }
            }
        }
        return mDownloadQueue;
    }

    /**
     * 图片请求
     *
     * @param url      地址
     * @param listener 回调
     */
    public void sendImageRequest(String url, final CommonResponseListener listener) {
        Request<Bitmap> request = NoHttp.createImageRequest(url, RequestMethod.GET);
        if (TextUtils.isEmpty(url)) {
            LogUtil.e(tag, "url is empty");
            return;
        }
        if (url.startsWith("https")) {
            //SSLContextUtil.doHttps(request);
        }
        mRequestQueue.add(assignWhatValue(), request, new OnResponseListener<Bitmap>() {
            @Override
            public void onStart(int what) {

            }

            @Override
            public void onSucceed(int what, Response<Bitmap> response) {
                List data = new ArrayList();
                data.add(response.get());
                listener.requestSuccess(data, "success");
            }

            @Override
            public void onFailed(int what, Response<Bitmap> response) {
                listener.requestFailed(mApplication.getString(R.string.networkError), Log.WARN);
            }

            @Override
            public void onFinish(int what) {
                recoverWhatValue(what);
            }
        });
    }

    /**
     * 上传文件
     *
     * @param url
     * @param postMap
     * @param fileKey
     * @param postFile
     * @param listener
     */
    public void uploadFile(final String url, Map<String, String> postMap, String fileKey, File postFile, final CommonResponseListener listener) {
        Request<String> request = NoHttp.createStringRequest(url, RequestMethod.POST);
        request.add(postMap);
        request.add(fileKey, new FileBinary(postFile));
        if (url.startsWith("https")) {
            SSLContextUtil.doHttps(request, mApplication);
        }
        mRequestQueue.add(assignWhatValue(), request, new OnResponseListener<String>() {
            @Override
            public void onStart(int what) {

            }

            @Override
            public void onSucceed(int what, Response<String> response) {
                List data = new ArrayList();
                try {
                    JSONObject jsonObject = new JSONObject(response.get());
                    if (jsonObject.getInt("status") == 1) {
                        listener.requestSuccess(data, jsonObject.getString("msg"));
                    } else {
                        listener.requestFailed(jsonObject.getString("msg"), Log.WARN);
                    }
                } catch (JSONException e) {
                    listener.requestFailed(mApplication.getString(R.string.networkError), Log.WARN);
                }

            }

            @Override
            public void onFailed(int what, Response<String> response) {
                listener.requestFailed(mApplication.getString(R.string.networkError), Log.WARN);
            }

            @Override
            public void onFinish(int what) {

            }
        });
    }


    /**
     * 下载
     *
     * @param url
     * @param fileFolder
     * @param filename
     * @param listener
     */
    public void download(String url, String fileFolder, String filename, final DownloadResponseListener listener) {
        DownloadRequest request = NoHttp.createDownloadRequest(url, RequestMethod.GET, fileFolder, filename, true, true);
        if (url.startsWith("https")) {
            SSLContextUtil.doHttps(request, mApplication);
        }
        mDownloadQueue.add(assignWhatValue(), request, new DownloadListener() {
            @Override
            public void onDownloadError(int what, Exception exception) {
                listener.onFailure(exception.getMessage(), Log.ERROR);
            }

            @Override
            public void onStart(int what, boolean isResume, long rangeSize, Headers responseHeaders, long allCount) {

            }

            @Override
            public void onProgress(int what, int progress, long fileCount) {
                listener.onProgress(progress);
            }

            @Override
            public void onFinish(int what, String filePath) {
                recoverWhatValue(what);
                listener.onSuccess(filePath);
            }

            @Override
            public void onCancel(int what) {

            }
        });
    }

    public interface DownloadResponseListener {
        void onProgress(int progress);

        void onSuccess(String filePath);

        void onFailure(String msg, int loglever);
    }

    /**
     * 异步加密请求
     */
    public void asyncPostStringEncryptRequest(String url, Map<String, String> map, CommonResponseListener listener) {
        asyncPostStringRequest(url, assignWhatValue(), map, listener);
    }

    /**
     * 异步不加密请求
     */
    public void asyncPostStringNoEncryptRequest(String url, Map<String, String> map, CommonResponseListener listener) {
        asyncPostStringRequest(url, assignWhatValue(), map, listener);
    }

    /**
     * 异步请求总入口
     */
    private void asyncPostStringRequest(String url, int what, Map<String, String> map, CommonResponseListener listener) {
//        LogUtil.i(tag, "asyncPostStringRequest:\nurl=" + url + "\nwhat=" + what);
        // 取消队列中已开始的请求
        mRequestQueue.cancelBySign(what);

        // 创建请求对象
        Request<String> request = NoHttp.createStringRequest(url, RequestMethod.POST);
        request.setHeader("appVersion", getAppCurrentVersion());

        if (map == null) {
            map = new HashMap<>();
        }
        LogUtil.i(tag, "接收到服务器请求\n请求链接:" + url + " \n请求参数:" + map);
        request.add(map);

        // 设置请求取消标志
        request.setCancelSign(what);
        //设置超时
        request.setConnectTimeout(10000);
        /**
         * 客户端请求使用短连接,尝试解决以下异常
         *  03-14 09:49:18.547: W/System.err(6270): java.io.EOFException
         03-14 09:49:18.547: W/System.err(6270):     at libcore.io.Streams.readAsciiLine(Streams.java:203)
         03-14 09:49:18.547: W/System.err(6270):     at libcore.net.http.HttpEngine.readResponseHeaders(HttpEngine.java:573)
         03-14 09:49:18.547: W/System.err(6270):     at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:821)
         03-14 09:49:18.547: W/System.err(6270):     at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:283)
         03-14 09:49:18.547: W/System.err(6270):     at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:495)
         03-14 09:49:18.547: W/System.err(6270):     at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)
         */
        if (Build.VERSION.SDK != null && Build.VERSION.SDK_INT > 13) {
            request.setHeader("Connection", "close");
        }
        //https加密
        if (url.startsWith("https")) {
            SSLContextUtil.doHttps(request, mApplication);
        }
//        LogUtil.i(tag, "NoHttp request Start:" + formatter.format(new Date()) + "," + url);

        //what = changeWhat(-1);
        // 向请求队列中添加请求
        // what: 当多个请求同时使用同一个OnResponseListener时，用来区分请求，类似Handler中的what
        mRequestQueue.add(what, request, listener);
    }

    /**
     * 异步请求响应结果回调对象
     */
    public abstract static class CommonResponseListener implements OnResponseListener<String> {

        Class clazz;

        public CommonResponseListener() {
        }

        public CommonResponseListener(Class clazz) {
            this.clazz = clazz;
        }

        @Override
        public void onSucceed(int what, Response<String> response) {
            int responseCode = response.getHeaders().getResponseCode();
            if (responseCode > 400) {
                requestFailed(mApplication.getString(R.string.networkError), Log.WARN);
                LogUtil.e(tag, "responseCode > 400,responseCode=" + responseCode);
                return;
            }
            String resultString = response.get();
            List<String> stringList = new ArrayList<>();
            stringList.add(resultString);
            if (clazz == null) {
                requestSuccess(stringList, "success");
                return;
            }
            //LogUtil.i(tag, "服务器请求结束\n请求链接:" + response.url() + "\n服务器响应的数据:" + resultString);
            if (!response.request().url().contains("showStandardPageItem.action")) {
                LogUtil.i(tag, "服务器请求结束，请求链接:" + response.request().url() + "\n服务器响应的数据:" + resultString);
            }
            JSONObject jsonResult;
            try {
                jsonResult = new JSONObject(resultString);
                int status = jsonResult.getInt("status");
                String data = jsonResult.getString("data");
                String msg = jsonResult.getString("msg");
                LogUtil.i(tag, "status=" + status + "\ndata=" + data + "\nmsg=" + msg);
                if (status != HTTP_REQUEST_SUCCESS) {
                    //状态为-1，例：同步设备失败
                    requestFailed(msg, (-1 == status ? Log.INFO : Log.WARN));
                    return;
                }
                List list = BeanUtil.antiSerializationJsonString(data, clazz);
                if (!response.request().url().contains("showStandardPageItem.action")) {
                    LogUtil.i(tag, "return list object=" + list);
                }
                requestSuccess(list, msg);
            } catch (JSONException e) {
                e.printStackTrace();
                requestFailed(mApplication.getString(R.string.networkError), Log.WARN);
            }
        }

        @Override
        public void onFailed(int what, Response<String> response) {
            Exception exception = response.getException();
            exception.printStackTrace();
            String errorMsg;
            if (exception instanceof NetworkError) {// 网络不好
                errorMsg = mApplication.getString(R.string.networkError);
                LogUtil.e(tag, "nohttp_network_error");
            } else if (exception instanceof TimeoutError) {// 请求超时
                errorMsg = mApplication.getString(R.string.networkError);
                LogUtil.e(tag, "nohttp_timeout_error");
            } else if (exception instanceof UnKnownHostError) {// 找不到服务器
                errorMsg = mApplication.getString(R.string.networkError);
                LogUtil.e(tag, "nohttp_unknownhost_error");
            } else if (exception instanceof URLError) {// URL是错的
                errorMsg = mApplication.getString(R.string.networkError);
                LogUtil.e(tag, "nohttp_url_error");
            } else if (exception instanceof NotFoundCacheError) {
                // 这个异常只会在仅仅查找缓存时没有找到缓存时返回
                errorMsg = mApplication.getString(R.string.networkError);
                LogUtil.e(tag, "nohttp_notfoundcache_error");
            } else if (exception instanceof ProtocolException) {
                errorMsg = mApplication.getString(R.string.networkError);
                LogUtil.e(tag, "nohttp_protocol_error");
            } else {
                errorMsg = mApplication.getString(R.string.networkError);
                LogUtil.e(tag, "nohttp_unknown_error");
                //errorMsg+=exception.toString();
            }
            requestFailed(errorMsg, Log.WARN);
        }

        @Override
        public void onStart(int what) {

        }

        @Override
        public void onFinish(int what) {
            recoverWhatValue(what);
        }

        public abstract void requestSuccess(List data, String msg);

        public abstract void requestFailed(String error, int loglever);
    }

    private static String getAppCurrentVersion() {
        String appVersion = "";
        PackageManager manager = mApplication.getPackageManager();
        try {
            PackageInfo info = manager.getPackageInfo(mApplication.getPackageName(), 0);
            appVersion = info.versionName;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return appVersion;
    }

    public static boolean checkNetworkAvailable(Context context) {
        if (context == null) {
            throw new IllegalArgumentException("参数异常");
        }
        ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivity == null) {
            return false;
        } else {
            NetworkInfo[] info = connectivity.getAllNetworkInfo();
            if (info != null) {
                for (NetworkInfo anInfo : info) {
                    if (anInfo.getState() == NetworkInfo.State.CONNECTED) {
                        if (anInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                            LogUtil.i(tag, "当前是wifi网络环境");
                            return true;
                        } else if (anInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
                            LogUtil.i(tag, "当前是移动网络环境");
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

}
